home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / cmln0286.arc / XMODEM.S < prev   
Text File  |  1986-02-03  |  6KB  |  273 lines

  1.  
  2.                    Taken from Kent Williams's 
  3.                    State Machines in C article
  4.                       February 1986 C issue
  5.  
  6.                             XMODEM.S
  7.  
  8. /* 
  9.  * xmodem.s
  10.  * implementation of xmodem protocol
  11.  * source for state machine compiler statecom
  12.  */
  13.  
  14. #include <stdio.h>ì
  15. #include <fcntl.h>ì
  16. #define TIMEOUT 0xFFFFì
  17. #define TICKSPERSEC 18ì
  18. #define SECSIZ 128ì
  19. #define RETRYMAX 10ì
  20. #define SOH    1ì
  21. #define EOT 4ì
  22. #define ACK 6ì
  23. #define NAK 21ì
  24. #define SECSIZ 128
  25.  
  26. typedef struct {
  27.     unsigned char soh;
  28.     unsigned char sectnum;
  29.     unsigned char sectcomp;
  30.     char buffer[SECSIZ];
  31.     unsigned char checksum;ì
  32. } packet;
  33.  
  34. typedef char sector[128];
  35.  
  36. extern timeout_read();    /* returns character if received, else -1 */ì
  37. extern async_write();    /* writes a buffer to async port */ìèextern async_putc();    /* writes one character to async port */
  38.  
  39. $machine xsend init (file) char *file;
  40.  
  41. /* machine global variables */ì
  42. int sectnum,attempts,fd;ì
  43. unsigned testchar;ì
  44. packet block;
  45.  
  46.  
  47. $state init
  48.     attempts = 0;
  49.     if (-1 == (fd = open(file, O_RDONLY)))
  50.     {
  51.         fprintf(stderr,"can't open %s\n",file);
  52.         $nextstate error    
  53.     }
  54.     fprintf(stderr,"Waiting for initial NAK ... attempt ");
  55.     $nextstate waitfornakì
  56. $endstate init
  57.  
  58. $state waitfornak
  59.     if (attempts > RETRYMAX)
  60.     {
  61.         fprintf(stderr,"none recieved - aborting\n");
  62.         $nextstate error
  63.     }
  64.     if (NAK != (testchar = timeout_read(5)))
  65.     {
  66.         ++attempts;
  67.         printf("# %d ",attempts);
  68.         $nextstate waitfornak
  69.     }
  70.     fprintf(stderr,"\nreceived!\n");
  71.     attempts = 0;
  72.     sectnum = 1;
  73.     $nextstate getpacket    ì
  74. $endstate waitfornak
  75.  
  76. $state getpacket
  77.     register int actual_read,i;
  78.     unsigned char checksum;
  79.     block.soh = SOH;
  80.     block.sectnum = (char) sectnum;
  81.     block.sectcomp = (char) ~sectnum;
  82.     switch(actual_read = read(fd,&(block.buffer[0]),SECSIZ))
  83.     {
  84.     case SECSIZ:
  85.         break;        /* everything's ok */
  86.     case 0:
  87.         $nextstate endoffile
  88.     default:
  89.         /* fractional sector */
  90.         for( ; actual_read < SECSIZ; actual_read++)
  91.             block.buffer[actual_read] = 0;è        break;
  92.     }
  93.     for (i = 0,checksum = 0; i < SECSIZ; i++)
  94.         checksum = 0xFF & (checksum + block.buffer[i]);
  95.     block.checksum = checksum;
  96.     $nextstate sendpacketì
  97. $endstate getpacket
  98.  
  99. $state sendpacket
  100.     if (attempts >= RETRYMAX)
  101.     {
  102.         fprintf(stderr,"too many retries - aborting\n");
  103.         $nextstate error
  104.     }
  105.     else
  106.     {
  107.         fprintf(stderr,"sending sector %d\r",sectnum);
  108.         async_write(&block,sizeof(packet));
  109.         $nextstate waitforack
  110.     }ì
  111. $endstate sendpacket
  112.  
  113. $state waitforack
  114.     if (ACK == timeout_read(4))
  115.     {
  116.         sectnum++;
  117.         attempts = 0;
  118.         $nextstate getpacket
  119.     } else
  120.     {
  121.         attempts++;
  122.         $nextstate sendpacket
  123.     }ì
  124. $endstate waitforack
  125.  
  126. $state endoffile
  127.     if (attempts > RETRYMAX)
  128.     {
  129.         fprintf(stderr,"no acknowledgement for end of file\n");
  130.         $nextstate error
  131.     }
  132.     async_putc(EOT);
  133.     if(ACK != (testchar = timeout_read(2)))
  134.     {
  135.         ++attempts;
  136.         $nextstate endoffile
  137.     } 
  138.     fprintf(stderr,"end of file acknowledged\n");
  139.     $nextstate done    ì
  140. $endstate endoffile
  141.  
  142. $state error
  143.     fprintf(stderr,"error encountered in file transmission\n");
  144.     close(fd);
  145.     $nextstate doneìè$endstate error
  146.  
  147. $state done
  148.     close(fd);
  149.     $nextstate terminalì
  150. $endstate done
  151.  
  152. $endmachine xsend
  153.  
  154. $machine xreceive rinit (file) char *file;
  155.  
  156. /* uses global variables in common with send */ì
  157. int sectnum,attempts,fd;ì
  158. unsigned testchar;ì
  159. sector *sp;
  160.  
  161.  
  162. $state rinit
  163.     if (-1 == (fd = creat(file,0666)))
  164.     {
  165.         fprintf(stderr,"can't create %s\n",file);
  166.         return -1;
  167.     }
  168.     attempts = 0;
  169.     sectnum = 1;    /* start at one */
  170.     fprintf(stderr,"sending NAK ");
  171.     $nexstate sendnakì
  172. $endstate rinit
  173.  
  174. $state sendnak
  175.     if (attempts >= RETRYMAX)
  176.     {
  177.         fprintf(stderr,"aborting ...\n");
  178.         $nextstate rerror
  179.     }
  180.     fprintf(stderr,"#%d ",attempts);
  181.     /* send naks until soh */
  182.     async_putc(NAK);
  183.     if (SOH != (testchar = timeout_read(10)))
  184.     {
  185.         ++attempts;
  186.         $nextstate sendnak
  187.     }
  188.     attempts = 0;
  189.     $nextstate getsector    ì
  190. $endstate sendnak
  191.  
  192. $state getsector
  193.     static sector buf;
  194.     int testchar;
  195.     register unsigned int checksum;
  196.     register int i;
  197.     if (attempts >= RETRYMAX)
  198.         $nextstate rerror
  199.     fprintf(stderr,"receiving sector %d\r",sectnum);è    if ((testchar = timeout_read(3)) != sectnum)
  200.     {
  201.         fprintf(stderr,"\nexpected sector %d got %d\n",sectnum,testchar);
  202.         ++attempts;
  203.         $nextstate waitforsilence
  204.     }
  205.     if ((testchar = timeout_read(3)) != (0xFF & (~sectnum)))
  206.     {
  207.         fprintf(stderr,"\nsector complement error, expected %d, got %d\n",
  208.         testchar,~sectnum & 0xFF);
  209.         ++attempts;
  210.         $nextstate waitforsilence
  211.     }
  212.     /* get a block */
  213.     checksum = 0;
  214.     for (i = 0;i < SECSIZ; i++)
  215.     {
  216.         checksum = 0xFF & (checksum + (buf[i] = timeout_read(3)));
  217.     }
  218.     if (checksum != (testchar = timeout_read(3)))
  219.     {
  220.         fprintf(stderr,"\nchecksum error\n,expected %d, got %d",
  221.         checksum,testchar);
  222.         attempts++;
  223.         async_putc(NAK);
  224.         $nextstate waitforsoh
  225.     }
  226.     write(fd,&buf,sizeof(sector));
  227.     async_putc(ACK);
  228.     attempts = 0;
  229.     sectnum++;
  230.     $nextstate waitforsohì
  231. $endstate getsector
  232.  
  233. $state waitforsoh
  234.     if (attempts >= RETRYMAX)
  235.         $nextstate rerror
  236.     switch (timeout_read(4))
  237.     {
  238.     case SOH:
  239.         $nextstate getsector
  240.     case TIMEOUT:
  241.         attempts++;
  242.         fprintf(stderr,"\ntimeout on SOH\n");
  243.         $nextstate waitforsoh
  244.     case EOT:
  245.         async_putc(ACK);
  246.         fprintf(stderr,"\nend of file received\n");
  247.         $nextstate rdone
  248.     default:
  249.         attempts++;
  250.         $nextstate waitforsilence
  251.     }ì
  252. $endstate waitforsoh
  253. è$state waitforsilence
  254.     /* re-sync between sectors */
  255.     do
  256.     {
  257.     }
  258.     while (TIMEOUT != timeout_read(1));
  259.     $nextstate waitforsohì
  260. $endstate waitforsilence
  261.  
  262. $state rerror
  263.     fprintf(stderr,"Error receiving file\n");
  264.     $nextstate rdoneì
  265. $endstate rerror
  266.  
  267. $state rdone
  268.     close(fd);
  269.     $nextstate terminalì
  270. $endstate rdone
  271.  
  272. $endmachine xreceive
  273.